package com.ac.service;

import java.util.ArrayList;
import java.util.List;

import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ac.exception.RRException;
import com.ac.model.AuthApi;
import com.ac.model.AuthMenu;
import com.ac.model.AuthPhone;
import com.ac.model.AuthRole;
import com.ac.model.AuthToken;
import com.ac.model.AuthUser;
import com.ac.model.Page;
import com.ac.model.query.AuthUserQ;
import com.ac.response.HttpStatus;
import com.ac.util.AESUtils;
import com.ac.util.AuthConf;
import com.ac.util.MongoUtil;
import com.ac.util.StrUtils;
import com.ac.util.ValUtils;

import cn.hutool.core.util.IdUtil;
import lombok.AllArgsConstructor;

@Service
@AllArgsConstructor
public class AuthUserService {

	private final AuthRoleService RoleService;

	private final AuthTokenService TokenService;

	final MongoTemplate mongo;

	public Page list(AuthUserQ uq) {
		Criteria ct = Criteria.where("id").exists(true).and("parentId").is(uq.getParentId());
		return MongoUtil.findPge(uq, AuthUser.class, ct);
	}

	/**
	 * 参数校验
	 */
	public void userVal(AuthUser user) {
		ValUtils.notNull(user.getName(), "名称");
		ValUtils.notNull(user.getAccount(), "账号");
		ValUtils.notNull(user.getPassword(), "密码");
		ValUtils.notArray(user.getRoleList(), "角色列表");
	}

	@Transactional(rollbackFor = Exception.class)
	public void insert(AuthUser user) {
		userVal(user);
		String account = user.getAccount();
		AuthUser userInfoa = mongo.findOne(Query.query(Criteria.where("account").is(account)), AuthUser.class);
		if (userInfoa != null) {
			if (user.getAccount().equals(userInfoa.getAccount()))
				throw new RRException("账号已存在");
		}

		user.setPhone("");

		isRoleList(user.getParentId(), user.getRoleList());
		user.insert();

		String password = user.getPassword();
		user.setPassword(AESUtils.encrypt(password, user.getId()));

		mongo.insert(user);

	}

	@Transactional(rollbackFor = Exception.class)
	public void update(AuthUser user) {
		userVal(user);
		String account = user.getAccount();
		AuthUser userInfo = mongo.findOne(Query.query(Criteria.where("id").is(user.getId())), AuthUser.class);
		AuthUser userInfoa = mongo.findOne(Query.query(Criteria.where("account").is(account)), AuthUser.class);
		if (userInfoa != null) {
			if (!userInfo.getId().equals(userInfoa.getId()))
				throw new RRException("账号已存在");
		}

		isRoleList(user.getParentId(), user.getRoleList());
		user.update();
		Update update = new Update();
		update.set("name", user.getName());
		update.set("account", account);
		update.set("status", user.isStatus());
		update.set("desc", user.getDesc());
		update.set("roleList", user.getRoleList());
		update.set("updateTime", user.getUpdateTime());
		mongo.updateFirst(Query.query(Criteria.where("id").is(user.getId())), update, AuthUser.class);
	}

	/**
	 * 判断是否具备创建或修改角色列表
	 */
	public void isRoleList(String parentId, List<String> uRoleList) {
		AuthUser parentInfo = info(parentId, true);
		List<AuthRole> pRoleList = RoleService.roleList(parentInfo, new Document());
		List<String> pRoleListStr = new ArrayList<String>();
		for (AuthRole authRole : pRoleList) {
			pRoleListStr.add(authRole.getId());
		}
		for (int i = 0; i < uRoleList.size(); i++) {
			if (!pRoleListStr.contains(uRoleList.get(i)))
				throw new RRException("非法操作", HttpStatus.BUG);
		}
	}

	@Transactional(rollbackFor = Exception.class)
	public void remove(AuthUser user) {
		mongo.remove(user);
		String userId = user.getId();
		Query query = Query.query(Criteria.where("userId").is(userId));
		mongo.remove(query, AuthToken.class);
	}

	@SuppressWarnings("unchecked")
	public Document login(Document map) {
		String token = "";
		List<AuthMenu> menuList = new ArrayList<AuthMenu>();
		List<AuthApi> apiList = new ArrayList<AuthApi>();
		String userAgent = map.getString("userAgent");
		String ip = map.getString("ip");
		Document res = new Document();
		if (map.containsKey("account")) {
			String account = map.getString("account");
			String password = map.getString("password");

			Criteria c1 = Criteria.where("account").is(account);
			AuthUser user = mongo.findOne(new Query(c1), AuthUser.class);
			if (user == null)
				throw new RRException("账号或密码错误");
			boolean status = user.isStatus();
			if (!status)
				throw new RRException("账号被禁用");
			password = AESUtils.encrypt(password, user.getId());
			Document resDoc = TokenService.createToken(user, new Document("password", password)
					.append("userAgent", userAgent).append("ip", ip).append("isPhone", false));
			token = resDoc.getString("token");
			menuList = (List<AuthMenu>) resDoc.get("menuList");
			apiList = (List<AuthApi>) resDoc.get("apiList");

		} else {
			String phone = map.getString("phone");
			ValUtils.isPhone(phone);
			String code = map.getString("code");
			ValUtils.isNumber(code, "验证码");
			String parentId = map.getString("parentId");
			AuthPhone phoneInfo = mongo.findOne(new Query(Criteria.where("phone").is(phone)), AuthPhone.class);
			if (phoneInfo == null)
				throw new RRException("请发送验证码");

			int errNum = phoneInfo.getErrNum();
			if (errNum > AuthConf.phoneErrNum)
				throw new RRException("请重新发送验证码");
			if (code.equals(phoneInfo.getCode())) {

				// 输入成功后立即删除验证码
				mongo.remove(Query.query(Criteria.where("phone").is(phone)), AuthPhone.class);

				// 登录成功
				AuthUser userInfo = mongo.findOne(new Query(Criteria.where("phone").is(phone)), AuthUser.class);
				if (userInfo == null) {
					AuthUser user = new AuthUser();
					if (StrUtils.isEmpty(parentId))
						parentId = AuthConf.phoneRegUserId;
					AuthUser pUserInfo = mongo.findOne(new Query(Criteria.where("id").is(parentId)), AuthUser.class);
					if (pUserInfo == null)
						throw new RRException("登录失败-U");
					user.setParentId(parentId);
					AuthRole roleInfo = mongo.findOne(new Query(Criteria.where("id").is(AuthConf.phoneRegRoleId)),
							AuthRole.class);
					if (roleInfo == null)
						throw new RRException("登录失败-R");
					List<String> roleList = new ArrayList<String>();
					roleList.add(AuthConf.phoneRegRoleId);
					user.setRoleList(roleList);
					isRoleList(user.getParentId(), user.getRoleList());
					user.setAccount(phone + StrUtils.getRandom(1000, 9999));
					user.setPassword(IdUtil.fastUUID());
					user.setName(phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
					user.setStatus(true);
					user.setPhone(phone);

					user.insert();
					userInfo = user;
					mongo.insert(user);
				}
				Document resDoc = TokenService.createToken(userInfo,
						new Document("userAgent", userAgent).append("ip", ip).append("isPhone", true));
				token = resDoc.getString("token");
				menuList = (List<AuthMenu>) resDoc.get("menuList");
				apiList = (List<AuthApi>) resDoc.get("apiList");
			} else {
				Update update = new Update();
				update.set("errNum", errNum + 1);
				mongo.updateFirst(Query.query(Criteria.where("phone").is(phone)), update, AuthPhone.class);
				throw new RRException("验证码错误");
			}

		}

		res.append("token", token);
		res.append("menuList", menuList);
		res.append("apiList", apiList);
		return res;

	}

	@Transactional(rollbackFor = Exception.class)
	public void resetPW(Document map) {
		String userId = map.getString("__userId");
		String old = map.getString("old");
		ValUtils.notNull(old, "老密码");
		old = AESUtils.encrypt(old, userId);
		String newstr = map.getString("newstr");
		ValUtils.notNull(newstr, "新密码");
		newstr = AESUtils.encrypt(newstr, userId);
		AuthUser info = info(userId, true);
		String infoPassword = info.getPassword();
		if (infoPassword.equals(old)) {
			Update update = new Update();
			update.set("password", newstr);
			mongo.updateFirst(Query.query(Criteria.where("id").is(userId)), update, AuthUser.class);
		} else {
			throw new RRException("老密码错误");
		}
	}

	/**
	 * 
	 * 根据用户id获取用户信息
	 * 
	 * @param token
	 * @return
	 */
	public AuthUser info(String id, boolean isAll) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(id).and("status").is(true));
		if (!isAll)
			query.fields().exclude("password", "roleList", "parentId", "status");
		AuthUser userInfo = mongo.findOne(query, AuthUser.class);
		if (userInfo == null)
			throw new RRException("用户不存在");
		return userInfo;
	}

	/**
	 * 根据用户id保存用户信息
	 */
	public void saveInfo(AuthUser user) {
		ValUtils.notNull(user.getName(), "名称");
		ValUtils.notNull(user.getDesc(), "描述");
		user.update();
		Update update = new Update();
		update.set("name", user.getName());
		update.set("desc", user.getDesc());
		mongo.updateFirst(Query.query(Criteria.where("id").is(user.getId())), update, AuthUser.class);
	}

}
